﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Topro.Util
{
    /// <summary>
    /// 加密解密工具
    /// </summary>
    public class EncryptionUtil
    {

        /// <summary>
        /// SHA256加密
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string enSHA256(string str)
        {
            if (string.IsNullOrEmpty(str) || string.IsNullOrWhiteSpace(str)) return "";
            SHA256 sha256 = new SHA256CryptoServiceProvider();
            var resultSha256 = sha256.ComputeHash(ASCIIEncoding.UTF8.GetBytes(str));
            sha256.Clear();
            return BitConverter.ToString(resultSha256).Replace("-", "").ToLower();
        }

        /// <summary>
        /// 对字符串附加随机字符进行MD5加密
        /// </summary>
        /// <param name="str">要加密的字符串</param>
        /// <param name="offset">加密所需的偏移量</param>
        /// <returns>加密后的小写字符串</returns>
        public static string EncryptWithMd5AndSalt(string str, string offset)
        {
            return EncryptWithMd5(offset + str) + ":" + offset;
        }

        /// <summary>
        /// 对字符串进行MD5加密
        /// </summary>
        /// <param name="str">要加密的字符串</param>
        /// <returns>加密后的小写字符串</returns>
        public static string EncryptWithMd5(string str)
        {
            using (var md5 = MD5.Create())
            {
                var result = md5.ComputeHash(ASCIIEncoding.UTF8.GetBytes(str));

                md5.Clear();

                return BitConverter.ToString(result).Replace("-", "").ToLower();
            }
        }

        /// <summary>
        /// 对字符串附加随机字符进行MD5加密
        /// </summary>
        /// <param name="str">要加密的字符串</param>
        /// <returns>加密后的小写字符串</returns>
        public static string EncryptWithMd5AndSalt(string str)
        {
            string password = "";
            password = new Random().Next(10000000, 99999999).ToString();
            string salt = EncryptWithMd5(password).Substring(0, 2);
            password = EncryptWithMd5(salt + str) + ":" + salt;
            return password;
        }

        /// <summary>
        /// 对加密字符串（字符串附加随机字符进行MD5加密后的字符串）进行验证
        /// </summary>
        /// <param name="unencrypted">明文</param>
        /// <param name="encrypted">密文</param>
        /// <returns>验证结果</returns>
        public static bool VerifyCiphetrextWithMd5AndSalt(string unencrypted, string encrypted)
        {
            if (!string.IsNullOrEmpty(unencrypted) && !string.IsNullOrEmpty(encrypted))
            {
                string[] stack = encrypted.Split(':');
                if (stack.Length != 2) return false;
                if (EncryptWithMd5(stack[1] + unencrypted) == stack[0])
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 计算参数签名
        /// </summary>
        /// <param name="parameters">请求参数集，所有参数必须已转换为字符串类型</param>
        /// <param name="secret">签名密钥</param>
        /// <returns>签名</returns>
        public static string GetSignature(IDictionary<string, string> parameters, string secret)
        {
            // 先将参数以其参数名的字典序升序进行排序
            IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
            var iterator = sortedParams.GetEnumerator();

            // 遍历排序后的字典，将所有参数按"key=value"格式拼接在一起
            var signBuilder = new StringBuilder();
            while (iterator.MoveNext())
            {
                string key = iterator.Current.Key;
                string value = iterator.Current.Value;
                if (!string.IsNullOrEmpty(key) && key != "Sign" && !string.IsNullOrEmpty(value))
                {
                    signBuilder.Append(key).Append("=").Append(value).Append("&");
                }
            }
            //basestring.Append(secret);
            var basestring = signBuilder.ToString();
            basestring = basestring.Substring(0, basestring.Length - 1);
            return HMAC(basestring, secret);
        }

        /// <summary>
        /// ToHexString
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToHexString(byte[] bytes)
        {
            string hexString = string.Empty;
            if (bytes != null)
            {
                StringBuilder strB = new StringBuilder();

                for (int i = 0; i < bytes.Length; i++)
                {
                    strB.Append(bytes[i].ToString("x2"));
                }
                hexString = strB.ToString();
            }
            return hexString;
        }

        /// <summary>
        /// HMACSHA256
        /// </summary>
        /// <param name="strText">文本</param>
        /// <param name="secret">密钥</param>
        /// <returns></returns>
        public static string HMAC(string strText, string secret)
        {
            var encoding = new UTF8Encoding();
            byte[] keyByte = encoding.GetBytes(secret);
            byte[] messageBytes = encoding.GetBytes(strText);
            using (var hmacsha256 = new HMACSHA256(keyByte))
            {
                byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                return ToHexString(hashmessage);
            }
        }

        private const string DefaultEncryptKey = "04ef51bcd5ebe089d3fa84afa7810af704ef51bcd5ebe0";

        /// <summary>
        /// DES加密字符串
        /// </summary>
        /// <param name="encryptString">待加密的字符串</param>
        /// <param name="encryptKey">加密密钥,要求为8位</param>
        /// <returns>加密成功返回加密后的字符串，失败返回源串</returns>
        public static string EnCryptDES(string encryptString)
        {
            try
            {
                byte[] rgbKey = Encoding.UTF8.GetBytes(DefaultEncryptKey.Substring(0, 8));
                byte[] rgbIV = { 0xBF, 0xAC, 0x26, 0x78, 0x90, 0x34, 0x1D, 0x1F };
                byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
                DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
                System.IO.MemoryStream mStream = new System.IO.MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return Convert.ToBase64String(mStream.ToArray());
            }
            catch
            {
                return encryptString;
            }
        }

        /// <summary>
        /// DES解密字符串
        /// </summary>
        /// <param name="decryptString">待解密的字符串</param>
        /// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param>
        /// <returns>解密成功返回解密后的字符串，失败返源串</returns>
        public static string DeCryptDES(string decryptString)
        {
            try
            {
                byte[] rgbKey = Encoding.UTF8.GetBytes(DefaultEncryptKey.Substring(0, 8));
                byte[] rgbIV = { 0xBF, 0xAC, 0x26, 0x78, 0x90, 0x34, 0x1D, 0x1F };
                byte[] inputByteArray = Convert.FromBase64String(decryptString);
                DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
                System.IO.MemoryStream mStream = new System.IO.MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return Encoding.UTF8.GetString(mStream.ToArray());
            }
            catch
            {
                return decryptString;
            }
        }
    }
}
